package com.zhihuishu.micro.course.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;

import com.github.abel533.mapper.Mapper;
import com.google.common.collect.Sets;
import com.zhihuishu.micro.course.dao.ChapterMapper;
import com.zhihuishu.micro.course.dao.LessonVideoMapper;
import com.zhihuishu.micro.course.dto.LessonVideoDto;
import com.zhihuishu.micro.course.model.Chapter;
import com.zhihuishu.micro.course.model.CourseVideoForBatis;
import com.zhihuishu.micro.course.model.LessonVideo;
import com.zhihuishu.micro.course.service.CourseBuildService;
import com.zhihuishu.micro.course.service.CourseService;
import com.zhihuishu.micro.course.service.LessonVideoService;
import com.zhihuishu.toolkit.helper.BeanHelper;
import com.zhihuishu.toolkit.jedis.JedisHelper;
import com.zhihuishu.toolkit.jedis.JedisHelper.Handler;

@Service("lessonVideoService")
public class LessonVideoServiceImpl extends BaseServiceImpl<LessonVideo> implements LessonVideoService {

    @Resource
    private LessonVideoMapper lessonVideoMapper;

    @Resource
    private ChapterMapper chapterMapper;

    @Resource
    private CourseService courseService;

    @Resource
    private CourseBuildService courseBuildService;

    private LessonVideoDto toDto(LessonVideo model) {
        if (model == null)
            return null;
        LessonVideoDto dto = new LessonVideoDto();
        dto.setId(model.getId());
        dto.setLessonId(model.getLessonId());
        dto.setName(model.getName());
        dto.setRank(model.getSort());
        dto.setVideoId(model.getVideoId());
        dto.setVideoSec(model.getVideoSec());
        dto.setVideoImg(model.getVideoImg());
        dto.setSpeaker(model.getSpeaker());
        dto.setCourseId(model.getCourseId());
        dto.setChapterId(model.getChapterId());
        dto.setHasKnowledegPoint(model.getHasKnowledegPoint());
        return dto;
    }

    private LessonVideo toModel(LessonVideoDto lessonVideoDto) {
        LessonVideo lessonVideo = new LessonVideo();
        lessonVideo.setId(lessonVideoDto.getId());
        lessonVideo.setCourseId(lessonVideoDto.getCourseId());
        lessonVideo.setChapterId(lessonVideoDto.getChapterId());
        lessonVideo.setLessonId(lessonVideoDto.getLessonId());
        lessonVideo.setLessonName(lessonVideoDto.getName());
        lessonVideo.setSort(lessonVideoDto.getRank());
        lessonVideo.setSpeaker(lessonVideoDto.getSpeaker());
        lessonVideo.setVideoId(lessonVideoDto.getVideoId());
        lessonVideo.setVideoImg(lessonVideoDto.getVideoImg());
        lessonVideo.setVideoUrl(lessonVideoDto.getVideoUrl());
        lessonVideo.setVideoSec(lessonVideoDto.getVideoSec());
        lessonVideo.setHasKnowledegPoint(lessonVideoDto.getHasKnowledegPoint());
        return lessonVideo;
    }

    @Override
    public LessonVideoDto get(final Integer lessonVideoId) {
        final LessonVideoDto lessonVideoDto = new LessonVideoDto();
        jedisExecutor.execute(new Handler() {

            @Override
            public void handle(Jedis jedis) {
                LessonVideoDto temp = new LessonVideoDto();
                Map<String, String> hash = jedis.hgetAll(JedisHelper.key("cc:lv", lessonVideoId));

                if (CollectionUtils.isEmpty(hash)) {
                    temp = touchLessonVideo(lessonVideoId);

                } else {
                    temp = BeanHelper.transTo(hash, LessonVideoDto.class);
                }
                BeanHelper.copyProperties(temp, lessonVideoDto);

            }
        });
        return lessonVideoDto;
    }

    @Override
    public List<LessonVideoDto> list(int lessonId) {
        List<Integer> lessonVideoIds = lessonVideoMapper.list(lessonId);
        if (CollectionUtils.isEmpty(lessonVideoIds))
            return null;
        return this.list(lessonVideoIds);
    }

    private LessonVideoDto getFromDb(int lessonVideoId) {
        LessonVideo model = lessonVideoMapper.get(lessonVideoId);
        if (model == null || model.getId() == null)
            return null;
        return toDto(model);
    }

    @Override
    public void touchLessonVideo(final LessonVideoDto dto) {
        jedisExecutor.execute(new Handler() {

            @Override
            public void handle(Jedis jedis) {
                // 如果查到，转换为哈希结构并写入缓存
                if (dto != null && dto.getId() != null) {
                    // System.out.println(BeanHelper.describe(dto));
                    jedis.del(JedisHelper.key("cc:lv", dto.getId()));// 先清除 防止一些field无法清除
                    jedis.hmset(JedisHelper.key("cc:lv", dto.getId()), BeanHelper.describe(dto));

                }

            }
        });

    }

    @Override
    public LessonVideoDto touchLessonVideo(final int lessonVideoId) {
        final LessonVideoDto target = new LessonVideoDto();
        jedisExecutor.execute(new Handler() {
            @Override
            public void handle(Jedis jedis) {
                // 数据库查询章
                LessonVideoDto dto = getFromDb(lessonVideoId);
                // 如果查到，转换为哈希结构并写入缓存
                if (dto != null && dto.getId() != null) {
                    // System.out.println(BeanHelper.describe(dto));
                    jedis.del(JedisHelper.key("cc:lv", lessonVideoId));// 先清除 防止一些field无法清除
                    jedis.hmset(JedisHelper.key("cc:lv", lessonVideoId), BeanHelper.describe(dto));
                    BeanHelper.copyProperties(dto, target);
                }
            }
        });
        return target.getId() != null ? target : null;
    }

    @Override
    public void addLessonVideoOnCourseRedis(final long courseId, final int lessonVideoId) {
        // LessonVideoDto dto = getFromDb(lessonVideoId);
        jedisExecutor.execute(new Handler() {
            @Override
            public void handle(Jedis jedis) {
                jedis.sadd(JedisHelper.key("cc:course", courseId, "lvs"), String.valueOf(lessonVideoId));
            }
        });
        courseService.updateCourseVideoTotalRedis(courseId);
    }

    @Override
    public void removeLessonVideoOnCourseRedis(final long courseId, final int lessonVideoId) {
        jedisExecutor.execute(new Handler() {
            @Override
            public void handle(Jedis jedis) {
                jedis.srem(JedisHelper.key("cc:course", courseId, "lvs"), String.valueOf(lessonVideoId));
            }
        });
        courseService.updateCourseVideoTotalRedis(courseId);
    }

    @Override
    public int countVideos(List<Integer> chapterIds) {
        return lessonVideoMapper.countVideos(chapterIds);
    }

    @Override
    public List<LessonVideoDto> list(final List<Integer> lessonVideoIds) {
        if (CollectionUtils.isEmpty(lessonVideoIds))
            return null;
        final List<LessonVideoDto> list = new ArrayList<LessonVideoDto>();
        jedisExecutor.execute(new Handler() {
            @Override
            public void handle(Jedis jedis) {
                for (Integer lessonVideoId : lessonVideoIds) {
                    if (lessonVideoId == null)
                        continue;
                    // 根据主键从Redis中获取数据
                    LessonVideoDto dto = null;
                    Map<String, String> hash = jedis.hgetAll(JedisHelper.key("cc:lv", lessonVideoId));
                    if (!CollectionUtils.isEmpty(hash)) {
                        dto = touchLessonVideo(lessonVideoId);
                    } else {
                        dto = BeanHelper.transTo(hash, LessonVideoDto.class);
                    }
                    if (dto != null)
                        list.add(dto);
                }
            }
        });
        return list.isEmpty() ? null : list;
    }

    @Override
    public List<CourseVideoForBatis> getSmallLessonByCourseIds(List<Long> courseIds) {
        return lessonVideoMapper.getSmallLessonByCourseIds(courseIds);
    }

    @Override
    public List<LessonVideoDto> getLessonVideoListFromDb(Integer lessonId) {
        List<LessonVideoDto> resultList = null;
        List<LessonVideo> list = lessonVideoMapper.getLessonVideoListFromDb(lessonId);
        if (list != null && list.size() > 0) {
            resultList = new ArrayList<LessonVideoDto>();
            for (LessonVideo lessonVideo : list) {
                LessonVideoDto lessonVideoDto = new LessonVideoDto();
                lessonVideoDto = toDto(lessonVideo);
                resultList.add(lessonVideoDto);
            }
        }
        return resultList;
    }

    @Override
    public Integer saveLessonVideo(LessonVideoDto lessonVideoDto) {
        // 查询节下最大的小节序号
        int maxSort = lessonVideoMapper.queryMaxSortOfLesson(lessonVideoDto.getLessonId());
        if (logger.isDebugEnabled()) {
            logger.debug("查询到节{}下最大的小节序号为{}", lessonVideoDto.getLessonId(), maxSort);
        }
        lessonVideoDto.setRank(maxSort + 1);
        LessonVideo lessonVideo = toModel(lessonVideoDto);
        if (lessonVideo.getHasKnowledegPoint() == null) {// 如果没有知识点 设置为0
            lessonVideo.setHasKnowledegPoint(0);
        }
        lessonVideo.setIsDeleted(0);// 默认未删除
        lessonVideoMapper.insertSelective(lessonVideo);
        lessonVideoDto.setId(lessonVideo.getId());

        touchLessonVideo(lessonVideoDto);
        // 添加小节 默认小节所在的章为未通过
        Chapter chapter = new Chapter();
        chapter.setId(lessonVideo.getChapterId().intValue());
        chapter.setIsPass(0);// 未通过
        chapterMapper.updateByPrimaryKeySelective(chapter);
        // 更新第三步为未通过状态
        courseBuildService.updateCourseStepStat(lessonVideo.getCourseId(), 3, 0);
        return lessonVideo.getId();
    }

    @Override
    public void deleteLessonVideoInfo(Integer lessonId) {
        lessonVideoMapper.deleteLessonVideoInfo(lessonId);

    }

    @Override
    public int getLessonChildrenCount(Integer lessonId) {

        return lessonVideoMapper.queryLessonChildrenCount(lessonId);

    }

    @Override
    public void updateLessonVideo(LessonVideoDto lessonVideoDto) {
        LessonVideo lessonVideo = toModel(lessonVideoDto);
        lessonVideo.setUpdateTime(new Date());
        lessonVideoMapper.updateByPrimaryKeySelective(lessonVideo);

    }

    @Override
    public void deleteLessonVideo(Integer lessonVideoId) {
        LessonVideo lessonVideo = new LessonVideo();
        lessonVideo.setId(lessonVideoId);
        lessonVideo.setIsDeleted(1);
        lessonVideo.setUpdateTime(new Date());
        updateSelective(lessonVideo);

    }

    @Override
    public Mapper<LessonVideo> getMapper() {

        return lessonVideoMapper;
    }

    @Override
    public void updateMinusSortByLessonIdAndSort(Long lessonId, Integer rank) {
        lessonVideoMapper.updateMinusSortByLessonIdAndSort(lessonId, rank);

    }

    @Override
    public void updateLessonVideoSort(Integer id, int targetRank) {
        LessonVideo lessonVideo = new LessonVideo();
        lessonVideo.setId(id);
        lessonVideo.setUpdateTime(new Date());
        lessonVideo.setSort(targetRank);
        lessonVideoMapper.updateByPrimaryKeySelective(lessonVideo);

    }

    @Override
    public void updatePlussLessonVideoSortContaninSmall(int targetPosSmall, int orginPosBig, Long lessonId) {
        lessonVideoMapper.updatePlussLessonVideoSortContaninSmall(targetPosSmall, orginPosBig, lessonId);

    }

    @Override
    public List<Integer> queryPlusLessonVideoIdsContainSmall(int targetPosSmall, int orginPosBig,
            Long lessonId) {
        return lessonVideoMapper.queryPlusLessonVideoIdsContainSmall(targetPosSmall, orginPosBig, lessonId);
    }

    @Override
    public List<Integer> queryMinusLessonVideoIdContainBig(int orginPosSmall, int targetPosBig, Long lessonId) {
        return lessonVideoMapper.queryMinusLessonVideoIdContainBig(orginPosSmall, targetPosBig, lessonId);
    }

    @Override
    public void updateMinusLessonVideoSortContainBig(int orginPosSmall, int targetPosBig, Long lessonId) {
        lessonVideoMapper.updateMinusLessonVideoSortContainBig(orginPosSmall, targetPosBig, lessonId);

    }

    @Override
    public void updateLeessonVideoKnowledgeFlag(Integer tempLessonVideId, int i) {
        LessonVideo lessonVideo = new LessonVideo();
        lessonVideo.setId(tempLessonVideId);
        lessonVideo.setHasKnowledegPoint(i);// 是否含有知识点的状态
        lessonVideo.setUpdateTime(new Date());
        lessonVideoMapper.updateByPrimaryKeySelective(lessonVideo);

    }

    @Override
    public Set<String> queryLessonVideoIdsByCourseId(final long courseId) {
        List<Integer> lessonVideoIds = lessonVideoMapper.queryLessonVideoIdsByCourseId(courseId);
        if (logger.isDebugEnabled()) {
            logger.debug("查询到的小节id为{}", lessonVideoIds);
        }
        if (CollectionUtils.isEmpty(lessonVideoIds)) {
            return Sets.newHashSet();
        }

        addLessonVideoIdsToCache(courseId, lessonVideoIds);
        addLesosnVideoInfoToCache(lessonVideoIds);
        Set<String> set = new HashSet<String>();
        for (Integer temp : lessonVideoIds) {
            set.add(temp.toString());
        }
        return set;
    }

    private void addLesosnVideoInfoToCache(List<Integer> lessonVideoIds) {
        if (CollectionUtils.isEmpty(lessonVideoIds)) {
            return;
        }
        final List<LessonVideo> lessonVideos = lessonVideoMapper.getList(lessonVideoIds);
        if (logger.isDebugEnabled()) {
            logger.debug("查询到小节的信息为{}", lessonVideos);
        }
        jedisExecutor.execute(new Handler() {

            @Override
            public void handle(Jedis jedis) {
                Pipeline pipelined = jedis.pipelined();
                String key;
                Map<String, String> hash;
                for (LessonVideo lessonVideo : lessonVideos) {
                    key = JedisHelper.key("cc:lv", lessonVideo.getId());
                    hash = BeanHelper.describe(toDto(lessonVideo));
                    hash.put("rank", lessonVideo.getSort() == null ? "0" : lessonVideo.getSort().toString());
                    pipelined.hmset(key, hash);
                }
                pipelined.sync();

            }
        });

    }

    private void addLessonVideoIdsToCache(final long courseId, List<Integer> lessonVideoIds) {
        if (CollectionUtils.isEmpty(lessonVideoIds)) {
            return;
        }
        final String[] lessonVideoIdArr = new String[lessonVideoIds.size()];
        for (int i = 0; i < lessonVideoIds.size(); i++) {
            lessonVideoIdArr[i] = lessonVideoIds.get(i).toString();
        }
        jedisExecutor.execute(new Handler() {

            @Override
            public void handle(Jedis jedis) {

                jedis.sadd(JedisHelper.key("cc:course", courseId, "lvs"), lessonVideoIdArr);
            }
        });
    }

    @Override
    public List<Integer> getIdByCourseId(long courseId) {

        return lessonVideoMapper.queryLessonVideoIdsByCourseId(courseId);
    }

}